import pako from 'pako'

type CompressionMethod = 'gzip' | 'deflate'
type EncodingType = 'base64' | 'hex'

export class StringCompressor {
  /**
   * 压缩字符串为二进制数据
   * @param input 原始字符串
   * @param method 压缩方式（默认 gzip）
   * @returns 压缩后的 Uint8Array
   */
  static compress(input: string, method: CompressionMethod = 'gzip'): Uint8Array {
    const encoder = new TextEncoder()
    const data = encoder.encode(input)

    switch (method) {
      case 'gzip':
        return pako.gzip(data)
      case 'deflate':
        return pako.deflate(data)
      default:
        throw new Error(`Unsupported compression method: ${method}`)
    }
  }

  /**
   * 解压缩二进制数据为字符串
   * @param compressedData 压缩后的二进制数据
   * @param method 解压缩方式（需与压缩时一致）
   * @returns 原始字符串
   */
  static decompress(compressedData: Uint8Array, method: CompressionMethod = 'gzip'): string {
    let decompressedData: Uint8Array

    switch (method) {
      case 'gzip':
        decompressedData = pako.ungzip(compressedData)
        break
      case 'deflate':
        decompressedData = pako.inflate(compressedData)
        break
      default:
        throw new Error(`Unsupported decompression method: ${method}`)
    }

    return new TextDecoder().decode(decompressedData)
  }

  /**
   * 压缩字符串并转为指定编码（Base64 或 Hex）
   * @param input 原始字符串
   * @param method 压缩方式（默认 gzip）
   * @param encoding 输出编码（默认 base64）
   * @returns 编码后的字符串
   */
  static compressToEncodedString(
    input: string,
    method: CompressionMethod = 'gzip',
    encoding: EncodingType = 'base64',
  ): string {
    const compressed = this.compress(input, method)
    return this.uint8ArrayToEncodedString(compressed, encoding)
  }

  /**
   * 从编码字符串解压
   * @param encodedString 编码后的字符串（Base64 或 Hex）
   * @param method 解压缩方式（需与压缩时一致）
   * @param encoding 输入编码（默认 base64）
   * @returns 原始字符串
   */
  static decompressFromEncodedString(
    encodedString: string,
    method: CompressionMethod = 'gzip',
    encoding: EncodingType = 'base64',
  ): string {
    const compressedData = this.encodedStringToUint8Array(encodedString, encoding)
    return this.decompress(compressedData, method)
  }

  // ====================== 编码转换工具方法 ======================
  private static uint8ArrayToEncodedString(data: Uint8Array, encoding: EncodingType): string {
    switch (encoding) {
      case 'base64':
        return btoa(String.fromCharCode(...data))
      case 'hex':
        return Array.from(data)
          .map((byte) => byte.toString(16).padStart(2, '0'))
          .join('')
      default:
        throw new Error(`Unsupported encoding: ${encoding}`)
    }
  }

  private static encodedStringToUint8Array(
    encodedString: string,
    encoding: EncodingType,
  ): Uint8Array {
    switch (encoding) {
      case 'base64':
        return new Uint8Array([...atob(encodedString)].map((char) => char.charCodeAt(0)))
      case 'hex':
        const hexPairs = encodedString.match(/.{1,2}/g) || []
        return new Uint8Array(hexPairs.map((byte) => parseInt(byte, 16)))
      default:
        throw new Error(`Unsupported encoding: ${encoding}`)
    }
  }
}
